package com.sakura.oj.interceptor;

import com.sakura.oj.common.ErrorCode;
import com.sakura.oj.constant.CommonConstant;
import com.sakura.oj.exception.BusinessException;
import com.sakura.oj.model.properties.AuthProperties;
import com.sakura.oj.model.vo.LoginUserVO;
import com.sakura.oj.utils.RedisUtil;
import com.sakura.oj.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录拦截器
 */
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 路径匹配器
     */
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Resource
    private AuthProperties authProperties;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 获取请求路径
        String requestURI = request.getRequestURI();
        log.info("拦截到请求：{}", requestURI);

        // 判断是否需要拦截
        boolean needIntercept = isNeedIntercept(requestURI);
        if (!needIntercept) {
            return true;
        }

        // 获取请求头中的token
        String token = request.getHeader(authProperties.getName());
        if (StringUtils.isBlank(token)) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "未登录");
        }

        // 从Redis获取用户信息
        LoginUserVO loginUserVO = RedisUtil.getCacheObject(CommonConstant.AUTH_TOKEN_KEY + token);
        if (loginUserVO == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "登录状态已过期");
        }

        // 续期token
        RedisUtil.expire(CommonConstant.AUTH_TOKEN_KEY + token, authProperties.getTime(), authProperties.getUnit());
        RedisUtil.expire(CommonConstant.AUTH_USER_KEY + loginUserVO.getId(), authProperties.getTime(), authProperties.getUnit());

        // 存入ThreadLocal
        UserHolder.saveUser(loginUserVO);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 请求结束，清理ThreadLocal中的用户信息
        UserHolder.removeUser();
    }

    /**
     * 判断是否需要拦截
     *
     * @param requestURI 请求路径
     * @return 是否需要拦截
     */
    private boolean isNeedIntercept(String requestURI) {
        // 先检查是否在排除路径中
        for (String excludePath : authProperties.getExcludePath()) {
            if (antPathMatcher.match(excludePath, requestURI)) {
                return false;
            }
        }

        // 再检查是否在包含路径中
        for (String includePath : authProperties.getIncludePath()) {
            if (antPathMatcher.match(includePath, requestURI)) {
                return true;
            }
        }

        // 默认不拦截
        return false;
    }
} 